package util.collision;

import java.util.HashSet;

import objects.base.Collidable;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;

/**
 * This data structure splits the game world up into
 * a number of tiles. Objects overlapping a tile are
 * have references to them stored in a list,
 * which can then be accessed when need be.
 * 
 * This allows objects to only need to check for collision
 * against objects that are considered *nearby*, reducing
 * the computational complexity of collision checking
 * 
 * @author John
 */

// Java doesn't like creating generic hashes, so warnings for this are suppressed
@SuppressWarnings("unchecked")
public class SpaceHash
{
	public static final float HASH_SIZE = 16;
	
	private int hashWidth;
	private int hashHeight;
	
	private HashSet<Collidable>[][] tileHash;
	
	/**
	 * A constructor that initializes the hash lists.
	 */
	public SpaceHash(float width,float height)
	{
		hashWidth=(int)Math.ceil(width/HASH_SIZE);
		hashHeight=(int)Math.ceil(height/HASH_SIZE);
		
		tileHash = new HashSet[hashWidth][hashHeight];
		for (int i = 0; i < hashWidth; i++)
		{
			for (int j = 0; j < hashHeight; j++)
			{
				tileHash[i][j] = new HashSet<Collidable>();
			}
		}
	}
	
	/**
	 * Returns a list of objects overlapping the given tile.
	 * 
	 * @param x - The X position of the tile. 
	 * @param y - The Y position of the tile.
	 * @return - A HashSet containing a list of objects overlapping the tile.
	 */
	public HashSet<Collidable> getObjects(int x, int y)
	{
		if (x < 0 || x >= hashWidth || y < 0 || y >= hashHeight) return null;
		return tileHash[x][y];
	}
	
	/**
	 * Adds an object reference to a tile's list. 
	 * 
	 * @param x - The X position of the tile.
	 * @param y - The Y position of the tile.
	 * @param object - The object reference to add to the list.
	 */
	public void addCollidable(int x, int y, Collidable object)
	{
		if (x < 0 || x >= hashWidth || y < 0 || y >= hashHeight) return;
		tileHash[x][y].add(object);
	}
	
	/**
	 * Removes an object reference from a tile's list.
	 * 
	 * @param x - The X position of the tile.
	 * @param y - The Y position of the tile.
	 * @param object - The object reference to remove from the list.
	 */
	public void removeCollidable(int x, int y, Collidable object)
	{
		if (x < 0 || x >= hashWidth || y < 0 || y >= hashHeight) return;
		tileHash[x][y].remove(object);
	}
	
	public void render(Graphics g)
	{
		for (int i = 0; i < hashWidth; i++)
		{
			for (int j = 0; j < hashHeight; j++)
			{
				int sizeman = tileHash[i][j].size()*30;
				if (sizeman > 255) sizeman = 255;
				sizeman = 255-sizeman;
				g.setColor(new Color(sizeman,sizeman,sizeman,128));
				if(sizeman!=255)
					g.fillRect(i*HASH_SIZE,j*HASH_SIZE,HASH_SIZE,HASH_SIZE);
			}
		}
	}
}